﻿#pragma execution_character_set("utf-8")
#include "../ImGui/imgui_impl_dx11.h"
#include "../ImGui/imgui_impl_win32.h"
#include "animation.h"
#include <algorithm>
#include <chrono>
#include <d3d11.h>
#include <iostream>
#include <random>
#include <tchar.h>
#include <vector>

HWND AnimationSystem::hWnd = nullptr;
ID3D11Device* AnimationSystem::pDevice = nullptr;
ID3D11DeviceContext* AnimationSystem::pDeviceContext = nullptr;
IDXGISwapChain* AnimationSystem::pSwapChain = nullptr;
ID3D11RenderTargetView* AnimationSystem::mainRenderTargetView = nullptr;
float AnimationSystem::progress = 0.0f;
float AnimationSystem::prevProgress = 0.0f;
float AnimationSystem::progressSmooth = 0.0f;
std::vector<AnimationSystem::Particle> AnimationSystem::particles;
std::vector<AnimationSystem::TrailPoint> AnimationSystem::trailPoints;
std::mt19937 AnimationSystem::rng(std::random_device{}());

extern const unsigned char* dllResource;

bool AnimationSystem::Initialize() {
	int screenWidth = GetSystemMetrics(SM_CXSCREEN);
	int screenHeight = GetSystemMetrics(SM_CYSCREEN);

	WNDCLASSEX wc = {
		sizeof(WNDCLASSEX), CS_CLASSDC, WndProc, 0L, 0L,
		GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr,
		L"EZInjectorAnimation", nullptr
	};
	RegisterClassEx(&wc);

	hWnd = CreateWindowEx(
		WS_EX_TOPMOST | WS_EX_LAYERED,
		wc.lpszClassName,
		L"EZInjector Animation",
		WS_POPUP,
		0, 0, screenWidth, screenHeight,
		nullptr, nullptr, wc.hInstance, nullptr
	);

	SetLayeredWindowAttributes(hWnd, RGB(0, 0, 0), 255, LWA_COLORKEY);

	if (!CreateDeviceD3D(hWnd)) {
		CleanupDeviceD3D();
		UnregisterClass(wc.lpszClassName, wc.hInstance);
		return false;
	}

	ShowWindow(hWnd, SW_SHOWMAXIMIZED);
	UpdateWindow(hWnd);

	IMGUI_CHECKVERSION();
	ImGui::CreateContext();
	ImGuiIO& io = ImGui::GetIO();
	io.Fonts->AddFontFromFileTTF("C:\\Windows\\Fonts\\msyh.ttc", 24.0f, nullptr, io.Fonts->GetGlyphRangesChineseFull());// 加载中文字体，增大字体尺寸
	io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange;
	io.FontGlobalScale = 1.0f;

	ImGui::StyleColorsDark();
	ImGuiStyle& style = ImGui::GetStyle();
	style.WindowRounding = 0.0f;
	style.ChildRounding = 0.0f;
	style.PopupRounding = 0.0f;
	style.FrameRounding = 0.0f;
	style.GrabRounding = 0.0f;
	style.ScrollbarRounding = 0.0f;

	style.Colors[ImGuiCol_WindowBg].w = 0.0f;

	ImGui_ImplWin32_Init(hWnd);
	ImGui_ImplDX11_Init(pDevice, pDeviceContext);

	particles.reserve(2000);
	trailPoints.reserve(500);
	SpawnParticles(150);

	return true;
}

bool AnimationSystem::Render() {
	MSG msg;
	while (PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE)) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
		if (msg.message == WM_QUIT) {
			return false;
		}
	}

	static auto lastTime = std::chrono::high_resolution_clock::now();
	auto currentTime = std::chrono::high_resolution_clock::now();
	float deltaTime = std::chrono::duration<float, std::chrono::seconds::period>(currentTime - lastTime).count();
	lastTime = currentTime;

	deltaTime = (std::min)(deltaTime, 0.1f);

	UpdateProgressSmoothing(deltaTime);

	UpdateParticles(deltaTime);
	UpdateTrailPoints(deltaTime);

	static float spawnTimer = 0.0f;
	spawnTimer += deltaTime;
	float spawnInterval = 0.03f - (progress * 0.01f);
	if (spawnTimer > spawnInterval) {
		spawnTimer = 0.0f;
		int spawnCount = 4 + static_cast<int>(progress * 6);
		SpawnParticles(spawnCount);
	}

	ImGui_ImplDX11_NewFrame();
	ImGui_ImplWin32_NewFrame();
	ImGui::NewFrame();

	int screenWidth = GetSystemMetrics(SM_CXSCREEN);
	int screenHeight = GetSystemMetrics(SM_CYSCREEN);

	ImGui::SetNextWindowPos(ImVec2(0, 0));
	ImGui::SetNextWindowSize(ImVec2(static_cast<float>(screenWidth), static_cast<float>(screenHeight)));
	ImGui::Begin(
		"EZInjector Animation", nullptr,
		ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
		ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoInputs
	);

	ImDrawList* drawList = ImGui::GetWindowDrawList();
	ImVec2 windowPos = ImGui::GetWindowPos();
	ImVec2 centerPos(windowPos.x + screenWidth * 0.5f, windowPos.y + screenHeight * 0.5f);

	float circleRadius = 150.0f;

	drawList->AddCircleFilled(
		centerPos,
		circleRadius * 0.5f,
		ImGui::ColorConvertFloat4ToU32(ImVec4(0.4f, 0.8f, 1.0f, 0.7f)),
		128
	);

	drawList->AddCircle(
		centerPos,
		circleRadius * 0.8f,
		ImGui::ColorConvertFloat4ToU32(ImVec4(0.6f, 0.9f, 1.0f, 0.3f)),
		128,
		1.0f
	);

	drawList->AddCircleFilled(
		centerPos,
		circleRadius,
		ImGui::ColorConvertFloat4ToU32(ImVec4(0.1f, 0.2f, 0.4f, 0.5f)),
		128
	);

	for (const auto& particle : particles) {
		float alpha = particle.lifetime / particle.maxLifetime;
		ImVec4 color = particle.color;
		color.w = alpha;

		drawList->AddCircleFilled(
			ImVec2(windowPos.x + particle.position.x, windowPos.y + particle.position.y),
			particle.size * alpha,
			ImGui::ColorConvertFloat4ToU32(color)
		);

		drawList->AddCircleFilled(
			ImVec2(windowPos.x + particle.position.x, windowPos.y + particle.position.y),
			particle.size * alpha * 1.5f,
			ImGui::ColorConvertFloat4ToU32(ImVec4(color.x, color.y, color.z, alpha * 0.3f))
		);
	}

	ImVec2 textPos(windowPos.x + screenWidth * 0.5f, windowPos.y + screenHeight * 0.4f);

	const char* titleText = "Counter-Strike 2 Injector";
	const char* subText = GetStatusText();

	ImVec2 titleSize = ImGui::CalcTextSize(titleText);
	ImVec2 titlePos(windowPos.x + screenWidth * 0.5f - titleSize.x * 0.5f, textPos.y - 15.0f);

	float glowIntensity = 0.6f + (progress * 0.4f);
	for (int i = -4; i <= 4; i++) {
		for (int j = -4; j <= 4; j++) {
			if (i == 0 && j == 0) continue;
			float dist = sqrtf(static_cast<float>(i * i) + static_cast<float>(j * j));
			if (dist > 5.0f) continue;
			float alpha = glowIntensity * (5.0f - dist) / 5.0f;
			drawList->AddText(
				ImVec2(titlePos.x + i, titlePos.y + j),
				ImGui::ColorConvertFloat4ToU32(ImVec4(0.4f, 0.8f, 1.0f, alpha * 0.7f)),
				titleText
			);
		}
	}

	ImVec4 titleColor(0.8f, 0.95f, 1.0f, 1.0f);
	titleColor.x = 0.7f + (progress * 0.3f);
	drawList->AddText(titlePos, ImGui::ColorConvertFloat4ToU32(titleColor), titleText);

	ImVec2 subTextSize = ImGui::CalcTextSize(subText);
	ImVec2 subTextPos(windowPos.x + screenWidth * 0.5f - subTextSize.x * 0.5f, textPos.y + 20.0f);

	for (int i = -3; i <= 3; i++) {
		for (int j = -3; j <= 3; j++) {
			if (i == 0 && j == 0) continue;
			float dist = sqrtf(static_cast<float>(i * i) + static_cast<float>(j * j));
			if (dist > 3.0f) continue;
			float alpha = 0.3f * (3.0f - dist) / 3.0f;
			drawList->AddText(
				ImVec2(subTextPos.x + i, subTextPos.y + j),
				ImGui::ColorConvertFloat4ToU32(ImVec4(0.4f, 0.6f, 1.0f, alpha)),
				subText
			);
		}
	}
	drawList->AddText(subTextPos, ImGui::ColorConvertFloat4ToU32(ImVec4(0.8f, 0.8f, 1.0f, 0.95f)), subText);

	float barWidth = 400.0f;
	float barHeight = 20.0f;
	float barRadius = 10.0f;
	ImVec2 barCenter(windowPos.x + screenWidth * 0.5f, windowPos.y + screenHeight * 0.55f);
	ImVec2 barPos(barCenter.x - barWidth * 0.5f, barCenter.y - barHeight * 0.5f);

	drawList->AddRectFilled(
		barPos,
		ImVec2(barPos.x + barWidth, barPos.y + barHeight),
		ImGui::ColorConvertFloat4ToU32(ImVec4(0.1f, 0.15f, 0.25f, 0.8f)),
		barRadius
	);

	drawList->AddRect(
		barPos,
		ImVec2(barPos.x + barWidth, barPos.y + barHeight),
		ImGui::ColorConvertFloat4ToU32(ImVec4(0.2f, 0.4f, 0.8f, 0.5f)),
		barRadius,
		0,
		2.0f
	);

	ImColor progressColor;
	if (progress < 0.33f) {
		float t = progress * 3.0f;
		progressColor.Value.x = 0.4f + (0.1f * t);
		progressColor.Value.y = 0.6f + (0.3f * t);
		progressColor.Value.z = 1.0f;
		progressColor.Value.w = 0.95f;
	}
	else if (progress < 0.66f) {
		float t = (progress - 0.33f) * 3.0f;
		progressColor.Value.x = 0.5f - (0.1f * t);
		progressColor.Value.y = 0.9f;
		progressColor.Value.z = 1.0f - (0.2f * t);
		progressColor.Value.w = 0.95f;
	}
	else {
		float t = (progress - 0.66f) * 3.0f;
		progressColor.Value.x = 0.4f - (0.3f * t);
		progressColor.Value.y = 0.9f;
		progressColor.Value.z = 0.8f - (0.7f * t);
		progressColor.Value.w = 0.95f;
	}

	float progressWidth = barWidth * progressSmooth;
	if (progressWidth > 0) {
		drawList->AddRectFilled(
			barPos,
			ImVec2(barPos.x + progressWidth, barPos.y + barHeight),
			progressColor,
			barRadius
		);

		float glowHeight = barHeight * 0.6f;
		float glowPosY = barCenter.y - glowHeight * 0.5f;
		drawList->AddRectFilled(
			ImVec2(barPos.x, glowPosY),
			ImVec2(barPos.x + progressWidth, glowPosY + glowHeight),
			ImGui::ColorConvertFloat4ToU32(ImVec4(1.0f, 1.0f, 1.0f, 0.25f)),
			barRadius
		);
	}

	char progressText[32];
	snprintf(progressText, sizeof(progressText), "%.0f%%", progress * 100.0f);
	ImVec2 progressTextSize = ImGui::CalcTextSize(progressText);
	ImVec2 progressTextPos(
		barCenter.x - progressTextSize.x * 0.5f,
		barPos.y - progressTextSize.y - 10.0f
	);

	static float pulseTimer = 0.0f;
	pulseTimer += deltaTime;
	float pulseFactor = 0.6f + (sin(pulseTimer * 3.0f) * 0.5f) * 0.5f;

	for (int i = -3; i <= 3; i++) {
		for (int j = -3; j <= 3; j++) {
			if (i == 0 && j == 0) continue;
			float dist = sqrtf(static_cast<float>(i * i) + static_cast<float>(j * j));
			if (dist > 3.0f) continue;
			float alpha = 0.8f * (3.0f - dist) / 3.0f * pulseFactor;
			drawList->AddText(
				ImVec2(progressTextPos.x + i, progressTextPos.y + j),
				ImGui::ColorConvertFloat4ToU32(ImVec4(progressColor.Value.x, progressColor.Value.y, progressColor.Value.z, alpha)),
				progressText
			);
		}
	}
	drawList->AddText(progressTextPos, ImGui::ColorConvertFloat4ToU32(ImVec4(1.0f, 1.0f, 1.0f, 1.0f)), progressText);

	DrawTechDecorations(drawList, windowPos, screenWidth, screenHeight);

	ImGui::End();

	ImGui::Render();
	const float clear_color_with_alpha[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
	pDeviceContext->OMSetRenderTargets(1, &mainRenderTargetView, nullptr);
	pDeviceContext->ClearRenderTargetView(mainRenderTargetView, clear_color_with_alpha);
	ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData());

	pSwapChain->Present(1, 0);

	return true;
}

void AnimationSystem::SetProgress(float newProgress) {
	prevProgress = progress;
	progress = newProgress;
	if (progress < 0.0f) progress = 0.0f;
	if (progress > 1.0f) progress = 1.0f;

	if (fabs(progress - prevProgress) > 0.01f) {
		int screenWidth = GetSystemMetrics(SM_CXSCREEN);
		int screenHeight = GetSystemMetrics(SM_CYSCREEN);
		ImVec2 barCenter(static_cast<float>(screenWidth) * 0.5f, static_cast<float>(screenHeight) * 0.55f);
		float barRadius = 150.0f;

		SpawnRippleEffect(barCenter, barRadius);

		if (progress > 0.2f && prevProgress <= 0.2f ||
			progress > 0.4f && prevProgress <= 0.4f ||
			progress > 0.6f && prevProgress <= 0.6f ||
			progress > 0.8f && prevProgress <= 0.8f) {
			SpawnProgressMilestoneEffect(barCenter);
		}
	}
}

void AnimationSystem::SpawnParticles(int count) {
	int screenWidth = GetSystemMetrics(SM_CXSCREEN);
	int screenHeight = GetSystemMetrics(SM_CYSCREEN);

	float centerX = (float)screenWidth * 0.5f;
	float centerY = (float)screenHeight * 0.5f;
	float innerRadius = 150.0f;
	float outerRadius = 350.0f - (progress * 100.0f);

	std::uniform_real_distribution<float> angleDist(0.0f, 2.0f * 3.14159f);
	std::uniform_real_distribution<float> radiusDist(innerRadius, outerRadius);
	std::uniform_real_distribution<float> velDist(80.0f, 200.0f + (progress * 80.0f));
	std::uniform_real_distribution<float> sizeDist(3.0f, 6.0f);
	std::uniform_real_distribution<float> lifetimeDist(2.0f, 4.0f);

	float rMin = 0.3f + (progress * 0.1f);
	float rMax = 0.5f + (progress * 0.1f);
	float gMin = 0.6f + (progress * 0.1f);
	float gMax = 0.9f + (progress * 0.05f);
	float bMin = 0.9f;
	float bMax = 1.0f;

	std::uniform_real_distribution<float> colorDistR(rMin, rMax);
	std::uniform_real_distribution<float> colorDistG(gMin, gMax);
	std::uniform_real_distribution<float> colorDistB(bMin, bMax);

	for (int i = 0; i < count; ++i) {
		Particle particle;

		float angle = angleDist(rng);
		float radius = radiusDist(rng);
		particle.position.x = centerX + radius * cos(angle);
		particle.position.y = centerY + radius * sin(angle);

		float velMag = velDist(rng);
		particle.velocity.x = velMag * cos(angle);
		particle.velocity.y = velMag * sin(angle);

		particle.size = sizeDist(rng);
		particle.lifetime = particle.maxLifetime = lifetimeDist(rng);
		particle.color = ImVec4(colorDistR(rng), colorDistG(rng), colorDistB(rng), 0.9f);

		particles.push_back(particle);
	}
}

void AnimationSystem::DrawScanLines(ImDrawList* drawList, const ImVec2& windowPos, int screenWidth, int screenHeight) {
	float scanlineOpacity = 0.05f + (progress * 0.03f);
	float scanlineSpacing = 8.0f;

	for (float y = 0; y < screenHeight; y += scanlineSpacing) {
		ImVec4 color(0.1f, 0.3f, 0.6f, scanlineOpacity);
		drawList->AddLine(
			ImVec2(windowPos.x, windowPos.y + y),
			ImVec2(windowPos.x + screenWidth, windowPos.y + y),
			ImGui::ColorConvertFloat4ToU32(color),
			1.0f
		);
	}
}

void AnimationSystem::DrawTechCirclePattern(ImDrawList* drawList, const ImVec2& center, float radius) {
	for (float r = radius * 0.2f; r < radius; r += radius * 0.2f) {
		ImVec4 color(0.2f, 0.4f, 0.8f, 0.15f);
		drawList->AddCircle(
			center,
			r,
			ImGui::ColorConvertFloat4ToU32(color),
			32,
			1.0f
		);
	}

	for (int i = 0; i < 16; ++i) {
		float angle = (i * 2.0f * 3.14159f) / 16.0f;
		float x1 = center.x + radius * 0.3f * cos(angle);
		float y1 = center.y + radius * 0.3f * sin(angle);
		float x2 = center.x + radius * 0.9f * cos(angle);
		float y2 = center.y + radius * 0.9f * sin(angle);

		ImVec4 color(0.2f, 0.4f, 0.8f, 0.2f);
		drawList->AddLine(
			ImVec2(x1, y1),
			ImVec2(x2, y2),
			ImGui::ColorConvertFloat4ToU32(color),
			1.0f
		);
	}
}

void AnimationSystem::DrawTechDecorations(ImDrawList* drawList, const ImVec2& windowPos, int screenWidth, int screenHeight) {
	ImVec2 centerPos(windowPos.x + screenWidth * 0.5f, windowPos.y + screenHeight * 0.5f);

	float cornerSize = 100.0f + (progress * 50.0f);
	float cornerOpacity = 0.2f + (progress * 0.2f);

	DrawCornerDecoration(drawList, windowPos, ImVec2(0, 0), cornerSize, cornerOpacity, true, true);
	DrawCornerDecoration(drawList, ImVec2(windowPos.x + screenWidth, windowPos.y), ImVec2(0, 0), cornerSize, cornerOpacity, false, true);
	DrawCornerDecoration(drawList, ImVec2(windowPos.x, windowPos.y + screenHeight), ImVec2(0, 0), cornerSize, cornerOpacity, true, false);
	DrawCornerDecoration(drawList, ImVec2(windowPos.x + screenWidth, windowPos.y + screenHeight), ImVec2(0, 0), cornerSize, cornerOpacity, false, false);
}

void AnimationSystem::DrawCornerDecoration(ImDrawList* drawList, const ImVec2& cornerPos, const ImVec2& offset, float size, float opacity, bool left, bool top) {
	int dirX = left ? -1 : 1;
	int dirY = top ? -1 : 1;

	ImVec4 color(0.4f, 0.7f, 1.0f, opacity);
	drawList->AddLine(
		ImVec2(cornerPos.x + offset.x, cornerPos.y + offset.y),
		ImVec2(cornerPos.x + offset.x + dirX * size, cornerPos.y + offset.y),
		ImGui::ColorConvertFloat4ToU32(color),
		2.0f
	);
	drawList->AddLine(
		ImVec2(cornerPos.x + offset.x, cornerPos.y + offset.y),
		ImVec2(cornerPos.x + offset.x, cornerPos.y + offset.y + dirY * size),
		ImGui::ColorConvertFloat4ToU32(color),
		2.0f
	);

	ImVec4 secondaryColor(0.4f, 0.7f, 1.0f, opacity * 0.5f);
	for (float i = size * 0.2f; i < size; i += size * 0.2f) {
		drawList->AddLine(
			ImVec2(cornerPos.x + offset.x + dirX * i, cornerPos.y + offset.y),
			ImVec2(cornerPos.x + offset.x + dirX * i, cornerPos.y + offset.y + dirY * i * 0.3f),
			ImGui::ColorConvertFloat4ToU32(secondaryColor),
			1.0f
		);
		drawList->AddLine(
			ImVec2(cornerPos.x + offset.x, cornerPos.y + offset.y + dirY * i),
			ImVec2(cornerPos.x + offset.x + dirX * i * 0.3f, cornerPos.y + offset.y + dirY * i),
			ImGui::ColorConvertFloat4ToU32(secondaryColor),
			1.0f
		);
	}
}

void AnimationSystem::SpawnProgressMilestoneEffect(const ImVec2& center) {
	const int milestoneParticleCount = 50;
	std::uniform_real_distribution<float> angleDist(0.0f, 2.0f * 3.14159f);
	std::uniform_real_distribution<float> velDist(100.0f, 300.0f);
	std::uniform_real_distribution<float> sizeDist(2.0f, 8.0f);
	std::uniform_real_distribution<float> lifetimeDist(1.5f, 3.0f);

	ImVec4 baseColor(0.6f, 0.9f, 1.0f, 0.95f);

	for (int i = 0; i < milestoneParticleCount; ++i) {
		Particle particle;

		float angle = angleDist(rng);
		float distance = 100.0f + (rng() % 50);
		particle.position.x = center.x + distance * cos(angle);
		particle.position.y = center.y + distance * sin(angle);

		float velMag = velDist(rng);
		particle.velocity.x = velMag * cos(angle);
		particle.velocity.y = velMag * sin(angle);

		particle.size = sizeDist(rng);
		particle.lifetime = particle.maxLifetime = lifetimeDist(rng);
		particle.color = baseColor;

		particles.push_back(particle);
	}
}

void AnimationSystem::Shutdown() {
	ImGui_ImplDX11_Shutdown();
	ImGui_ImplWin32_Shutdown();
	ImGui::DestroyContext();

	CleanupDeviceD3D();

	UnregisterClass(L"EZInjectorAnimation", GetModuleHandle(nullptr));

	particles.clear();
	trailPoints.clear();
}

void AnimationSystem::UpdateTrailPoints(float deltaTime) {
	auto it = trailPoints.begin();
	while (it != trailPoints.end()) {
		TrailPoint& point = *it;
		point.lifetime -= deltaTime;
		if (point.lifetime <= 0.0f) {
			it = trailPoints.erase(it);
		}
		else {
			++it;
		}
	}
}

const char* AnimationSystem::GetStatusText() {
	if (progress < 0.2f) {
		return "准备注入环境...";
	}
	else if (progress < 0.4f) {
		return "加载DLL资源...";
	}
	else if (progress < 0.6f) {
		return "定位游戏进程...";
	}
	else if (progress < 0.8f) {
		return "注入游戏进程...";
	}
	else if (progress < 1.0f) {
		return "初始化注入模块...";
	}
	else {
		return "注入完成！";
	}
}

void AnimationSystem::UpdateProgressSmoothing(float deltaTime) {
	float smoothFactor = 5.0f;
	progressSmooth = progressSmooth + (progress - progressSmooth) * (1.0f - exp(-smoothFactor * deltaTime));
}

void AnimationSystem::UpdateParticles(float deltaTime) {
	auto it = particles.begin();
	while (it != particles.end()) {
		Particle& particle = *it;
		particle.position.x += particle.velocity.x * deltaTime;
		particle.position.y += particle.velocity.y * deltaTime;
		particle.lifetime -= deltaTime;

		static std::uniform_real_distribution<float> randDist(-10.0f, 10.0f);
		particle.position.x += randDist(rng) * deltaTime;
		particle.position.y += randDist(rng) * deltaTime;

		particle.velocity.x *= 0.99f;
		particle.velocity.y *= 0.99f;

		if (particle.lifetime <= 0.0f) {
			it = particles.erase(it);
		}
		else {
			++it;
		}
	}
}

void AnimationSystem::SpawnRippleEffect(const ImVec2& center, float radius) {
	const int rippleParticleCount = 20;
	std::uniform_real_distribution<float> angleDist(0.0f, 2.0f * 3.14159f);
	std::uniform_real_distribution<float> velDist(50.0f, 150.0f);
	std::uniform_real_distribution<float> sizeDist(2.0f, 4.0f);
	std::uniform_real_distribution<float> lifetimeDist(1.0f, 2.0f);

	for (int i = 0; i < rippleParticleCount; ++i) {
		Particle particle;
		float angle = angleDist(rng);
		float distance = radius * (0.8f + (rng() % 100) / 500.0f);

		particle.position.x = center.x + distance * cos(angle);
		particle.position.y = center.y + distance * sin(angle);

		float velMag = velDist(rng);
		particle.velocity.x = velMag * cos(angle);
		particle.velocity.y = velMag * sin(angle);

		particle.size = sizeDist(rng);
		particle.lifetime = particle.maxLifetime = lifetimeDist(rng);
		particle.color = ImVec4(0.4f, 0.8f, 1.0f, 0.8f);

		particles.push_back(particle);
	}
}

LRESULT CALLBACK AnimationSystem::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) {
	switch (msg) {
	case WM_SYSCOMMAND:
		if ((wParam & 0xfff0) == SC_KEYMENU)
			return 0;
		break;
	case WM_CLOSE:
		PostQuitMessage(0);
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_SIZE:
		if (pDevice != nullptr && wParam != SIZE_MINIMIZED) {
			if (mainRenderTargetView) {
				mainRenderTargetView->Release();
				mainRenderTargetView = nullptr;
			}

			pSwapChain->ResizeBuffers(0, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam), DXGI_FORMAT_UNKNOWN, 0);

			ID3D11Texture2D* pBackBuffer;
			pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
			pDevice->CreateRenderTargetView(pBackBuffer, nullptr, &mainRenderTargetView);
			pBackBuffer->Release();

			D3D11_VIEWPORT vp = {
				0.0f,
				0.0f,
				(float)LOWORD(lParam),
				(float)HIWORD(lParam),
				0.0f,
				1.0f
			};
			pDeviceContext->RSSetViewports(1, &vp);
		}
		return 0;
	}
	return DefWindowProc(hWnd, msg, wParam, lParam);
}

void AnimationSystem::CleanupDeviceD3D() {
	if (mainRenderTargetView) {
		mainRenderTargetView->Release();
		mainRenderTargetView = nullptr;
	}
	if (pSwapChain) {
		pSwapChain->Release();
		pSwapChain = nullptr;
	}
	if (pDeviceContext) {
		pDeviceContext->Release();
		pDeviceContext = nullptr;
	}
	if (pDevice) {
		pDevice->Release();
		pDevice = nullptr;
	}
}

bool AnimationSystem::CreateDeviceD3D(HWND hWnd) {
	DXGI_SWAP_CHAIN_DESC sd;
	ZeroMemory(&sd, sizeof(sd));
	sd.BufferCount = 2;
	sd.BufferDesc.Width = 0;
	sd.BufferDesc.Height = 0;
	sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	sd.BufferDesc.RefreshRate.Numerator = 60;
	sd.BufferDesc.RefreshRate.Denominator = 1;
	sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
	sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	sd.OutputWindow = hWnd;
	sd.SampleDesc.Count = 1;
	sd.SampleDesc.Quality = 0;
	sd.Windowed = TRUE;
	sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;

	D3D_FEATURE_LEVEL featureLevel;
	const D3D_FEATURE_LEVEL featureLevelArray[2] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0, };
	HRESULT res = D3D11CreateDeviceAndSwapChain(nullptr,
		D3D_DRIVER_TYPE_HARDWARE,
		nullptr,
		0,
		featureLevelArray,
		2,
		D3D11_SDK_VERSION,
		&sd,
		&pSwapChain,
		&pDevice,
		&featureLevel,
		&pDeviceContext);
	if (res == DXGI_ERROR_UNSUPPORTED)
		res = D3D11CreateDeviceAndSwapChain(nullptr,
			D3D_DRIVER_TYPE_WARP,
			nullptr,
			0,
			featureLevelArray,
			2,
			D3D11_SDK_VERSION,
			&sd,
			&pSwapChain,
			&pDevice,
			&featureLevel,
			&pDeviceContext);
	if (res != S_OK) {
		return false;
	}

	ID3D11Texture2D* pBackBuffer;
	pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer));
	pDevice->CreateRenderTargetView(pBackBuffer, nullptr, &mainRenderTargetView);
	pBackBuffer->Release();

	return true;
}